﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Windows.UI.Xaml.Controls;

namespace SudokuSolver.Classes.Core
{
    public class Sudoku
    {
        public static Cell[,] grid;

        public Sudoku()
        {
            grid = new Cell[9, 9];

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    grid[i, j] = new Cell(i + 1, j + 1);
                }
            }
        }

        #region public methods
        public void LoadFromString(String aTxtGrid)
        {
            String txtValue;

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    txtValue = aTxtGrid.Substring(i * 9 + j, 1);

                    if (!txtValue.Equals("."))
                    {
                        grid[i, j].Value = int.Parse(txtValue);
                        grid[i, j].WasPresent = true;
                    }
                }
            }
        }

        public bool Solve()
        {
            return Solve(grid);
        }

        public bool Solve(Cell[,] aGrid, int aStartIndex = 0)
        {
            int rowIndex = aStartIndex / 9;
            int columnIndex = aStartIndex % 9;

            // If aStartIndex 81 is reached, job is done!
            if (aStartIndex == 81)
            {
                return true;
            }

            if (aGrid[rowIndex, columnIndex].Value != 0)
            {
                return Solve(aGrid, aStartIndex + 1);
            }

            for (int supposedValue = 1; supposedValue < 10; supposedValue++)
            {
                if (IsConsistent(supposedValue, aGrid, rowIndex, columnIndex))
                {
                    aGrid[rowIndex, columnIndex].Value = supposedValue;

                    if (Solve(aGrid, aStartIndex + 1))
                    {
                        return true;
                    }
                }
            }

            aGrid[rowIndex, columnIndex].Value = 0;

            return false;
        }


        public ObservableCollection<Cell> GetData()
        {
            ObservableCollection<Cell> cells = new ObservableCollection<Cell>();

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    cells.Add(grid[i, j]);
                }
            }

            return cells;
        }

        public override string ToString()
        {
            StringBuilder strGrid = new StringBuilder();

            strGrid.Append("\n\n");

            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (grid[i, j].Value == 0)
                    {
                        strGrid.Append(" . ");
                    }
                    else
                    {
                        strGrid.Append(" " + grid[i, j] + " ");
                    }

                    if ((j + 1) % 3 == 0 && j != 8)
                    {
                        strGrid.Append("|");
                    }
                }

                strGrid.Append("\n");

                if ((i + 1) % 3 == 0 && i != 8)
                {
                    strGrid.Append("------|------|------\n");
                }
            }

            return strGrid.ToString();
        }

        public bool IsConsistentPad(int value, int rowIndex, int columnIndex)
        {
            return IsConsistent(value, grid, rowIndex, columnIndex);
        }
        #endregion

        #region private methods
        private bool CheckRow(int aValue, Cell[,] aGrid, int aRowIndex)
        {
            for (int i = 0; i < 9; i++)
            {
                if (aGrid[aRowIndex, i].Value == aValue)
                {
                    return false;
                }
            }

            return true;
        }

        private bool CheckColumn(int aValue, Cell[,] aGrid, int aColumnIndex)
        {
            for (int i = 0; i < 9; i++)
            {
                if (aGrid[i, aColumnIndex].Value == aValue)
                {
                    return false;
                }
            }

            return true;
        }

        private bool CheckSquare(int aValue, Cell[,] aGrid, int aRowIndex, int aColumnIndex)
        {
            int rowIndex = aRowIndex - (aRowIndex % 3);
            int columnIndex = aColumnIndex - (aColumnIndex % 3);

            for (int i = rowIndex; i < rowIndex + 3; i++)
            {
                for (int j = columnIndex; j < columnIndex + 3; j++)
                {
                    if (aGrid[i, j].Value == aValue)
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        private bool IsConsistent(int aSupposedValue, Cell[,] aGrid, int aRowIndex, int aColumnIndex)
        {
            return CheckRow(aSupposedValue, aGrid, aRowIndex) && CheckColumn(aSupposedValue, aGrid, aColumnIndex) && CheckSquare(aSupposedValue, aGrid, aRowIndex, aColumnIndex);
        }
        #endregion
    }
}